#define MSMEM_C
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libmslog/mslog.h>
#include "mscommon.h"
#include "mstime.h"
#include "msthread.h"

#define FLAG "MEMRY_MAP"

typedef struct MEMNODEContext{  
    ms_pvoid ptr;      
    ms_u32 size;   
    ms_u08 name[128];
	ms_u08 nameDes[1024];
    ms_u08 time[16];
    ms_u32 line;    
    ms_string filename;  
    struct MEMNODEContext *next; 
} MEMNODEContext;  
typedef struct MEMSContext{  
    ms_u08 name[128];
    ms_u32 size;   
	ms_u32 sizePer;   
	ms_bool flag_used;
} MEMSContext;  

static MEMSContext memsCtt[2048]={0};  
static MEMNODEContext *first_memnode_ctt = ms_null;  
static ms_void msmem_innerapi_nodeAdd( ms_pvoid ms_in ptr, ms_u32 ms_in size,ms_string name,ms_string nameDes, ms_string ms_in filename, ms_u32 ms_in  line)  
{
	ms_bufcheck(ptr);
	ms_bufcheck(filename);
	MEMNODEContext **p= &first_memnode_ctt;
	while ((*p) != ms_null){
		p = &(*p)->next;
	}
	MEMNODEContext* temp = (MEMNODEContext*)malloc(sizeof(MEMNODEContext));
	memset(temp, 0, sizeof(MEMNODEContext));
	temp->ptr = ptr;  
	temp->size = size;  
	ms_strcpy(temp->name, name);
	if(ms_null!=nameDes){
		ms_strcpy(temp->nameDes, nameDes);
	}
	ms_s08 str_curtime[64]={0};
	ms_sprintfs(temp->time,"%s",mstime_api_curTime(mstime_fmt_time,str_curtime));
	temp->line = line;  
	temp->filename = filename;  
	temp->next = ms_null;  
	*p = temp;	
} 
static ms_void msmem_innerapi_nodeRm(ms_pvoid ms_io ptr)
{
	ms_bufcheck(ptr);
	MEMNODEContext **p= &first_memnode_ctt;
	MEMNODEContext*pre_memnode_ctt=ms_null;
    	while ((*p) != ms_null){
		if((*p)->ptr==ptr){
			struct MEMNODEContext * addr_next=(struct MEMNODEContext *) ((*p)->next);
			free((*p));(*p)=ms_null;
			if( ms_null!=pre_memnode_ctt){
				pre_memnode_ctt->next=addr_next;
			}else{
				pre_memnode_ctt=(struct MEMNODEContext *)addr_next;
				first_memnode_ctt=pre_memnode_ctt;
			}
			return;
		}
		pre_memnode_ctt=(*p);
		p=&((*p)->next);
	}
}  
static MSLOCKContext msmem_mslock_ctt;
static ms_bool flag_init=ms_false;

static ms_bool msmem_enable_dbg=ms_false;

 ms_void msmem_api_init(ms_bool enable_debug)  
 {
 	if(ms_true==flag_init){
		return;
	}
 	msmem_enable_dbg=enable_debug;
	if(ms_true==msmem_enable_dbg){
		mslock_api_init(&msmem_mslock_ctt,"msmem_mslockctt",lockType_rw);
	 	flag_init=ms_true;
	}
 }
 ms_void msmem_api_deinit(ms_void)
 { 	if(ms_false==flag_init){
		return;
	}

  	flag_init=ms_false;
	mslock_api_deinit(&msmem_mslock_ctt);
 }
 
 ms_pvoid msmem_api_malloc(ms_u32 ms_in size,ms_string name,ms_string nameDes, ms_string ms_in filename, ms_u32 ms_in line)  
{  
	ms_bufcheckRet(ms_null,filename);
	//ms_pvoid ptr =malloc(size); 
	ms_pvoid ptr =calloc(1,size); 
	if(NULL==ptr){ 
		ms_errRet(ms_null,"Malloc %s failed,please check the memory",filename); 
	}else{ 
		memset(ptr,0,size); 
	}
	if(ms_true==msmem_enable_dbg){
		if(ms_true!=flag_init){
			ms_waring("Must init  msmem_mslock_ctt  first");
		}else{
			mslock_api_wd(&msmem_mslock_ctt);
			msmem_innerapi_nodeAdd(ptr, size, name,nameDes,filename, line);  
			mslock_api_undo(&msmem_mslock_ctt);
		}
	}
	return ptr;  
}  

 ms_pvoid msmem_api_calloc(ms_u32 ms_in size,ms_string name,ms_string nameDes, ms_string ms_in filename, ms_u32 ms_in line)  
{  
	ms_bufcheckRet(ms_null,filename);
	ms_pvoid ptr =calloc(1,size); 
	if(NULL==ptr){ 
		ms_errRet(ms_null,"Malloc %s failed,please check the memory",filename); 
	}else{ 
		memset(ptr,0,size); 
	}
	if(ms_true==msmem_enable_dbg){
		if(ms_true!=flag_init){
			ms_waring("Must init  msmem_mslock_ctt  first");
		}else{
			mslock_api_wd(&msmem_mslock_ctt);
			msmem_innerapi_nodeAdd(ptr, size, name,nameDes,filename, line);  
			mslock_api_undo(&msmem_mslock_ctt);
		}
	}
	return ptr;  
}  

 
ms_void msmem_api_free(ms_pvoid ms_io *pptr)  
{  
	if(ms_true==msmem_enable_dbg){
		if(ms_true!=flag_init){
			ms_waring("Must init  msmem_mslock_ctt  first");
		}else{
			mslock_api_wd(&msmem_mslock_ctt);
			msmem_innerapi_nodeRm((*pptr));  
			mslock_api_undo(&msmem_mslock_ctt);
		}
	}
	if(ms_null!=(*pptr)){
		free((*pptr));(*pptr)=ms_null;
	}
}  

ms_void msmem_api_showBlock(ms_void)
{
	if(ms_true==msmem_enable_dbg){
		if(ms_true!=flag_init){
			ms_errNoret("Must init  msmem_mslock_ctt  first");
		}
		mslock_api_rd(&msmem_mslock_ctt);
		MEMNODEContext **p= &first_memnode_ctt;
		ms_u32 total = 0;  
		ms_u32 memryleak_index=0;
		while ((*p) != ms_null){
			ms_debug("Memry leak[%08d]:addr ,size :%p   %s ---file,line %s %d", ++memryleak_index, (*p)->ptr,ms_Bb32AUTO_unit((*p)->size,ms_false),(*p)->filename, (*p)->line);	
			total += (*p)->size;   
			p=&(*p)->next;
		}
		mslock_api_undo(&msmem_mslock_ctt);
		ms_debug("Toal memry leak:%d byte", total);  
	}else{
		ms_funcNosupports;
	}
}

#define MSWEB_H2_STYLE 			"style=\"color:red;\""
#define MSWEB_FONT_STYLE 		"style=\"color:black;\""
ms_string msmem_innerapi_getFlagInfo(ms_u32 size)
{
	if(size<(10*ms_KB)){
		return "--";
	}else if(size<(500*ms_KB)){
		return "++";
	}else{
		return "高";
	}
}
ms_void msmem_innerapi_totalInfo(char *outbuf)
{
	char tempbuf[1024]={0};
	ms_strcats(tempbuf,outbuf,
		"<table cellpadding=\"4\" cellspacing=\"0\">");
	ms_strcats(tempbuf,outbuf,
			"<tbody "MSWEB_FONT_STYLE">");	
	
	ms_strcats(tempbuf,outbuf,
				"<tr>"
						"<th align=\"left\">"
					"序号</th>""<th align=\"left\"></th>"
						"<th align=\"left\">"					
					"名称</th>""<th align=\"left\"></th>"
						"<th align=\"left\">"
					"内存总量</th>""<th align=\"left\"></th>"
						"<th align=\"left\">"
					"标志(总量|分片)</th>""<th align=\"left\"></th>"
						"<th align=\"left\">"	
					"内存详情</th>""<th align=\"left\"></th>"
						"<th align=\"left\">"
				"</tr>");	
	ms_memset0(memsCtt, 2048*ms_bufsize(MEMSContext));
	mslock_api_rd(&msmem_mslock_ctt);
	MEMNODEContext **p= &first_memnode_ctt;
	ms_u32 total = 0;  
	while ((*p) != ms_null){
		for(ms_s32 memsCttIndex=0;memsCttIndex<2048;memsCttIndex++){
			if(ms_false==memsCtt[memsCttIndex].flag_used){
				memsCtt[memsCttIndex].flag_used=ms_true;
				ms_strcpy(memsCtt[memsCttIndex].name, (*p)->name);
				memsCtt[memsCttIndex].size=(*p)->size;
				memsCtt[memsCttIndex].sizePer=(*p)->size;
				break;
			}else if(ms_strncmp_saeq(memsCtt[memsCttIndex].name, (*p)->name)){
				memsCtt[memsCttIndex].size+=(*p)->size;
				memsCtt[memsCttIndex].sizePer=ms_min(memsCtt[memsCttIndex].sizePer, (*p)->size);
				break;
			}
		}
		total += (*p)->size;   
		p=&(*p)->next;
	}
			
	mslock_api_undo(&msmem_mslock_ctt);
	ms_strcats(tempbuf,outbuf,"<h4 "MSWEB_FONT_STYLE">内存申请总量:%s</h4>",ms_Bb32AUTO_unit(total,ms_false)) ;
	for(ms_s32 memsCttIndex=0;memsCttIndex<2048;memsCttIndex++){
		if(ms_false==memsCtt[memsCttIndex].flag_used){
			break;
		}else{
			ms_strcats(tempbuf,outbuf,"%s","<tr>");
			ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%08d</th>""<th align=\"left\"></th>",memsCttIndex);
			ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%s</th>""<th align=\"left\"></th>",memsCtt[memsCttIndex].name);
			ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%s</th>""<th align=\"left\"></th>",ms_Bb32AUTO_unit(memsCtt[memsCttIndex].size,ms_false));
			ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%s|%s</th>""<th align=\"left\"></th>",msmem_innerapi_getFlagInfo(memsCtt[memsCttIndex].size),msmem_innerapi_getFlagInfo(memsCtt[memsCttIndex].sizePer));
			ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%u 个%s片</th>""<th align=\"left\"></th>",memsCtt[memsCttIndex].size/memsCtt[memsCttIndex].sizePer,ms_Bb32AUTO_unit(memsCtt[memsCttIndex].sizePer,ms_false));
			ms_strcats(tempbuf,outbuf,"%s","</tr>");
		}
	}
	ms_strcats(tempbuf,outbuf,	
			"</tbody>");			
	ms_strcats(tempbuf,outbuf,	
		"</table>");
}
ms_void msmem_innerapi_desInfo(char *outbuf)
{
	char tempbuf[1024]={0};
	ms_strcats(tempbuf,outbuf,
		"<table cellpadding=\"4\" cellspacing=\"0\">");
	ms_strcats(tempbuf,outbuf,
				"<tbody "MSWEB_FONT_STYLE">");	
	ms_strcats(tempbuf,outbuf,
					"<tr>"
							"<th align=\"left\">"
						"序号</th>""<th align=\"left\"></th>"
							"<th align=\"left\">"					
						"名称|描述</th>""<th align=\"left\"></th>"
							"<th align=\"left\">"
						"内存大小</th>""<th align=\"left\"></th>"
							"<th align=\"left\">"
						"标志</th>""<th align=\"left\"></th>"
							"<th align=\"left\">"
						"地址</th>""<th align=\"left\"></th>"
							"<th align=\"left\">"
						"申请时间</th>""<th align=\"left\"></th>"
							"<th align=\"left\">"
						"函数所在文件</th>""<th align=\"left\"></th>"
							"<th align=\"left\">"		
						"函数所在行数</th>""<th align=\"left\"></th>"
							"<th align=\"left\">"		
					"</tr>");	
	mslock_api_rd(&msmem_mslock_ctt);
	MEMNODEContext **p= &first_memnode_ctt;
	ms_u32 memryleak_index=0;
	while ((*p) != ms_null){
		ms_strcats(tempbuf,outbuf,"%s","<tr>");
		ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%08d</th>""<th align=\"left\"></th>",++memryleak_index);
		if(ms_buflen((*p)->nameDes)){
			ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%s|%s</th>""<th align=\"left\"></th>",(*p)->name,(*p)->nameDes);
		}else{
			ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%s</th>""<th align=\"left\"></th>",(*p)->name);
		}
		ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%s</th>""<th align=\"left\"></th>",ms_Bb32AUTO_unit((*p)->size,ms_false));
		ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%s</th>""<th align=\"left\"></th>",msmem_innerapi_getFlagInfo((*p)->size));
		ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%p</th>""<th align=\"left\"></th>",(*p)->ptr);
		ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%s</th>""<th align=\"left\"></th>",(*p)->time);
		ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%s</th>""<th align=\"left\"></th>",(*p)->filename);
		ms_strcats(tempbuf,outbuf,"<th align=\"left\">""%d</th>""<th align=\"left\"></th>",(*p)->line);
		ms_strcats(tempbuf,outbuf,"%s","</tr>");
		p=&(*p)->next;
	}
	mslock_api_undo(&msmem_mslock_ctt);
	ms_strcats(tempbuf,outbuf,	
			"</tbody>");			
	ms_strcats(tempbuf,outbuf,	
		"</table>");
}
ms_void msmem_api_info(char *outbuf,ms_string disable_des)
{
	char tempbuf[1024]={0};
//network-info	
	if(ms_true==msmem_enable_dbg){
		if(ms_true!=flag_init){
			ms_strcats(tempbuf,outbuf,"<h4 "MSWEB_FONT_STYLE">Wait msmem init...</h4>") ;
			ms_errNoret("Must init  msmem_mslock_ctt  furst");
		}
		ms_u32 item_index=0;
		ms_strcats(tempbuf,outbuf,
			"<h2 "MSWEB_H2_STYLE">%03d.%s</h2>",(++item_index),"内存统计") ;
		msmem_innerapi_totalInfo(outbuf);
		ms_strcats(tempbuf,outbuf,
			"<h2 "MSWEB_H2_STYLE">%03d.%s</h2>",(++item_index),"内存详情") ;
		msmem_innerapi_desInfo(outbuf);
			
	}else{
		ms_strcats(tempbuf,outbuf,"<h4 "MSWEB_FONT_STYLE">%s</h4>",disable_des) ;
	}
}

ms_void msmem_api_test(ms_void)
{
	ms_s32 num=4;
	msmem_api_init(ms_true);  
	while(1){
		ms_pbyte* test[2000]={ms_null};
		ms_u32 index=0;
		ms_debug("========================%d===",num);
		ms_debug("BE------Malloc");
		for(index=0;index<2000;index++){
			ms_malloc_noRet(test[index], 2048*1024, "test");
		}
		ms_debug("AF------Malloc");	
		ms_sleep(3);
		ms_debug("BE------Free");	
		for(index=0;index<2000;index++){
			ms_deMalloc(test[index]);
		}
		ms_debug("AF------Free");	
		ms_debug("===========================");
		ms_sleep(3);
		if((--num)<0){
			break;
		}
	}
	msmem_api_deinit();  
}

#undef MSMEM_C

